package org.orz.cloud.lock;


import java.util.Stack;

/**
 * 当前线程的锁的持有对象，当前线程加的所有的锁都会保存在{@link LockHolder#localLock}中
 */
public class LockHolder {

	/**
	 * 存当前线程锁对象的栈对象，遵循先进后出的规则
	 */
	private ThreadLocal<Stack<Lock>> localLock = new ThreadLocal<Stack<Lock>>();

	/**
	 * 锁工厂对象
	 */
	private LockFactory<?> lockFactory;

	/**
	 * 私有无参构造方法，防止被直接从外部实例化
	 */
	private LockHolder(){}

	/**
	 * 获取LockHolder实例对象的方法
	 * @return LockHolder实例对象
	 */
	protected static LockHolder getInstance(){
		return SingletonFactory.instance;
	}

	/**
	 * 单例模式获取LockHolder实例
	 *
	 * JVM内部的机制能够保证当一个类被加载的时候，这个类的加载过程是线程互斥的。
	 * 这样当我们第一次调用getInstance()的时候，JVM能够帮助我们保证instance只被
	 * 创建一次，并且保证会把赋值给instance的内存初始化完毕
	 */
	private static class SingletonFactory{
		private static LockHolder instance = new LockHolder();
	}

	/**
	 * LockFactory的get()方法
	 * @return 锁工厂对象
	 */
	protected LockFactory<?> getLockFactory() {
		return lockFactory;
	}

	/**
	 * LockFactory的set()方法
	 * @param lockFactory 锁工厂对象
	 */
	protected void setLockFactory(LockFactory<?> lockFactory) {
		this.lockFactory = lockFactory;
	}

	/**
	 * 创建一个新的锁，放入栈{@link LockHolder#localLock}顶中，并返回该对象
	 * 在{@link LockUtil}中调用
	 *
	 * @return 新创建的锁
	 */
	protected Lock getLock(){
		Stack<Lock> stack = localLock.get();
		if(stack == null){
			stack = new Stack<>();
			localLock.set(stack);
		}
		stack.push(lockFactory.createLock());
		return stack.peek();
	}

	/**
	 * 从{@link LockHolder#localLock}中取出栈顶的锁，并释放
	 */
	protected void release(){
		Stack<Lock> stack = localLock.get();
		if(stack !=null && !stack.isEmpty()){
			Lock lock = stack.pop();
			if(lock != null){
				lock.release();
			}
		}
		if(stack == null || stack.isEmpty()){
			localLock.remove();
		}
	}
	
}
